<template>
	<div class="notifications-center" :class="classObject" ref="notificationsCenterRef">
		<div class="header">
			<span class="title beyond-hiding">{{
				store.message.list.length > 0 ? store.message.list.length + ' 条通知' : '无通知'
			}}</span>
			<div class="toolbar">
				<ul class="actions">
					<li
						class="action-item icon-button"
						title="关闭消息中心"
						@click="store.setNotificationsCenterShow(false)">
						<i class="iconfont icon-yuyinguanbi"></i>
					</li>
				</ul>
			</div>
		</div>
		<div class="container scroll" ref="containerRef">
			<message-item
				v-for="item in store.message.list"
				:key="item.id"
				:data="item"
				@remove="removeById(item.id)" />
		</div>
	</div>
</template>

<script setup lang="ts">
import { reactive, computed, ref, onMounted, onBeforeUnmount, watch, nextTick } from 'vue';
import { useRootStore } from '@v/store';
import messageItem from './message-item.vue';

const store = useRootStore();

const classObject = reactive({
	visible: computed(() => store.message.show),
});

const notificationsCenterRef = ref<HTMLDivElement>();
const containerRef = ref<HTMLDivElement>();

/**
 * 设置 container 的高度
 */
function setContainerHeight(s?: boolean, b?: boolean) {
	if (!store.message.show) return;

	function fn() {
		if (!containerRef.value) return;

		let height = 0;
		containerRef.value.querySelectorAll('.message-item').forEach((element) => {
			height += (element as HTMLDivElement).offsetHeight;
		});

		if (height + 35 > document.body.offsetHeight - 40) {
			height = document.body.offsetHeight - 75;
		}

		containerRef.value.style.setProperty('--container-height', height + 'px');

		if (b) {
			scrollTo('auto');
		}
	}

	if (s) {
		nextTick(fn);
	} else {
		fn();
	}
}

/**
 * 根据 id 删除消息
 */
function removeById(id: number) {
	store.removeMessage(id);
}

let seenId = store.message.seen;

// 滚动
function scrollTo(type: 'auto' | 'bottom' | 'top' = 'bottom') {
	if (!store.message.show) return;

	nextTick(() => {
		if (!containerRef.value) return;

		let y = -1;

		if (type === 'auto') {
			// seenId 不等于 0 且和最新的 id 不相等
			if (seenId !== 0 && seenId !== store.message.latest?.id) {
				const doms = containerRef.value.children;

				for (let i = 0; i < store.message.list.length; i++) {
					const item = store.message.list[i];

					if (item.id === seenId) {
						if (seenId !== 0) {
							y += doms[i].clientHeight;
						}
						break;
					}

					y += doms[i].clientHeight;
				}
			}
		} else if (type === 'bottom') {
			y = containerRef.value.scrollHeight;
		} else if (type === 'top') {
			y = 0;
		}

		if (y !== -1) containerRef.value?.scrollTo(0, y);

		seenId = store.message.seen;
	});
}

// 窗口大小变化回调
const resizeListener = () => {
	setContainerHeight();
};

// 添加窗口大小变化事件
window.addEventListener('resize', resizeListener);
// 组件卸载时移除窗口大小变化事件
onBeforeUnmount(() => window.removeEventListener('resize', resizeListener));

onMounted(() => {
	setContainerHeight(true);
});

// 监控消息中心是否展示
watch(
	() => store.message.show,
	(s) => {
		if (s) {
			setContainerHeight(true);

			const obj = store.message.list[store.message.list.length - 1];
			if (obj) store.setMessageSeen(obj.id);

			scrollTo('auto');
		}
	}
);

// 监控消息列表变化
let temp = 0;
watch(
	() => store.message.list,
	(n) => {
		// 消息增加时默认滚动到底部
		if (n.length > temp) {
			setContainerHeight(true, true);
		} else {
			setContainerHeight(true);
		}

		temp = n.length;
	},
	{ deep: true }
);
</script>

<style scoped lang="scss">
.notifications-center {
	position: absolute;
	bottom: calc(8px + 24px);
	left: 8px;
	display: none;
	width: 450px;
	border-radius: 4px;
	box-shadow: rgba(0, 0, 0, 0.36) 0px 0px 8px 2px;
	background-color: var(--fill-color-4);
	border: 1px solid var(--border-color-4);
	max-height: calc(100% - 40px);
	overflow: hidden;
	z-index: 99;

	&.visible {
		display: block;
	}
	.header {
		height: 35px;
		display: flex;
		align-items: center;
		padding: 0 7px 0 8px;
		background-color: var(--fill-color-3);
		.title {
			font-size: 13px;
			line-height: 100%;
			user-select: none;
		}
		.toolbar {
			flex: 1;
			.actions {
				display: flex;
				align-items: center;
				justify-content: flex-end;
				margin-right: 4px;
				.action-item {
					display: flex;
					align-items: center;
					justify-content: center;
					width: 20px;
					height: 20px;
					border-radius: 4px;
					margin-right: 4px;
					&:hover {
						background-color: var(--mouse-hover-bg-color-3);
					}
					&:last-child {
						margin-right: 0;
					}
					.iconfont {
						font-size: 14px;
					}
				}
			}
		}
	}

	.container {
		height: var(--container-height);
		overflow-x: hidden;
		scroll-behavior: smooth;
	}
}
</style>
